// 判断是否是元素标签
const isReservedTag = (tag) => {
  return ['a', 'div', 'p', 'button', 'span', 'ul', 'li'].includes(tag);
}

// 创建元素节点 _c() / h()
export function createElementVNode(vm, tag, data, ...children) {
  if (data == null) {
    data = {}
  }
  const key = data.key;
  if (key) {
    delete data.key;
  }
  if (isReservedTag(tag)) {
    // 是普通的元素标签
    return vnode(vm, tag, key, data, children);
  } else {
    // 不是元素标签就创建一个组件的虚拟节点
    // 找到组件的构造函数
    const Ctor = vm.$options.components[tag];
    // Ctor 就是组件的定义,可能是一个Sub类,也有可能是obj的选项
    return createComponentVNode(vm,tag,key,data,children,Ctor);
  }
}
function createComponentVNode(vm,tag,key,data,children,Ctor){
  if(typeof Ctor === 'object'){
    Ctor = vm.$options._base.extend(Ctor);
  }
  data.hook = {
    // 稍后创建真实节点时,如果是组件就会调用此init方法
    init(vnode){
      // 保存组件实例到虚拟节点上
      let instance = vnode.componentInstance = new vnode.componentOptions.Ctor;
      instance.$mount();
    }
  }
  return vnode(vm,tag,key,data,children,null,{Ctor})
}
// 创建文本节点 _v()
export function createTextVNode(vm, text) {
  return vnode(vm, undefined, undefined, undefined, undefined, text);
}
// 创建虚拟节点
// 形成的ast很像,ast是语法表面的转化,他描述的是语法本身
// 虚拟dom描述的是dom对象,可以增加一些自定义的属性,如插槽/指令等
function vnode(vm, tag, key, data, children, text,componentOptions) {
  return {
    vm,
    tag,
    key,
    data,
    children,
    text,
    componentOptions
  }
}

// 判断两个虚拟节点是不是同一个
export function isSameVNode(vnode1, vnode2) {
  return vnode1.tag === vnode2.tag && vnode1.key === vnode2.key;
}